package com.douyin.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.douyin.constant.AuditStatus;
import com.douyin.constant.RedisConstant;
import com.douyin.dto.RegisterDTO;
import com.douyin.dto.UpdateUserDTO;
import com.douyin.entity.Favorites;
import com.douyin.entity.User;
import com.douyin.entity.UserSubscribe;
import com.douyin.entity.response.AuditResponse;
import com.douyin.entity.video.Type;
import com.douyin.exception.BaseException;
import com.douyin.holder.UserHolder;
import com.douyin.mapper.FileMapper;
import com.douyin.mapper.UserMapper;
import com.douyin.service.*;
import com.douyin.service.audit.ImageAuditService;
import com.douyin.service.audit.TextAuditService;
import com.douyin.utils.RedisCacheUtil;
import com.douyin.vo.BasePage;
import com.douyin.vo.ModelVO;
import com.douyin.vo.UserModel;
import com.douyin.vo.UserVO;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IFavoritesService favoritesService;
    @Autowired
    private IFollowService followService;
    @Autowired
    private TextAuditService textAuditService;
    @Autowired
    private ImageAuditService imageAuditService;
    @Autowired
    private FileService fileService;
    @Autowired
    private FileMapper fileMapper;
    @Autowired
    private UserSubscribeService userSubscribeService;
    @Autowired
    private TypeService typeService;

    @Autowired
    private InterestPushService interestPushService;
    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Override
    public boolean register(RegisterDTO registerDTO) {
        long count =this.query().eq("email", registerDTO.getEmail()).count();
        if (count ==1){
            throw new BaseException("改邮箱已被注册");
        }
        Object code = stringRedisTemplate.opsForValue().get("emailCode:" + registerDTO.getEmail());
        if (code ==null){
            throw new BaseException("验证码已过期");
        }
        if (!registerDTO.getCode().equals(code)){
            throw new BaseException("验证码错误");
        }
        User user = new User();
        user.setEmail(registerDTO.getEmail());
        //加密
        user.setPassword(DigestUtils.md5DigestAsHex(registerDTO.getPassword().getBytes()));
        user.setNickName(registerDTO.getNickName());
        user.setDescription("无");
        this.save(user);

        //创建默认收藏夹
        Favorites favorites = new Favorites();
        favorites.setUserId(user.getId());
        favorites.setName("默认收藏夹");
        favoritesService.save(favorites);

        user.setDefaultFavoritesId(favorites.getId());
        this.updateById(user);
        return true;
    }

    @Override
    public UserVO getUserInfo(String userId) {
        User user = this.getById(userId);
        if (user == null){
            throw new BaseException("用户不存在");
        }
        UserVO userVO=new UserVO();
        BeanUtils.copyProperties(user,userVO);

        //查找粉丝数量和关注数量
        long followerCount = followService.getFollowerCount(userId);
        long fansCount = followService.getFansCount(userId);
        userVO.setFollow(followerCount);
        userVO.setFans(fansCount);
        return userVO;
    }

    @Override
    public void updateInfo(UpdateUserDTO updateUserDTO) {
        Long userId = updateUserDTO.getUserId();
        User oldUser = this.getById(userId);
        if (!oldUser.getNickName().equals(updateUserDTO.getNickName())){
            oldUser.setNickName(updateUserDTO.getNickName());
            final AuditResponse audit = textAuditService.audit(updateUserDTO.getNickName());
            if (audit.getAuditStatus() != AuditStatus.SUCCESS) {
                throw new BaseException(audit.getMsg());
            }
        }
        if (!ObjectUtils.isEmpty(updateUserDTO.getDescription()) && !oldUser.getDescription().equals(updateUserDTO.getDescription())){
            oldUser.setDescription(updateUserDTO.getDescription());
            final AuditResponse audit = textAuditService.audit(updateUserDTO.getDescription());
            if (audit.getAuditStatus() != AuditStatus.SUCCESS) {
                throw new BaseException(audit.getMsg());
            }
        }

        if (!Objects.equals(updateUserDTO.getAvatar(),oldUser.getAvatar())){
                AuditResponse audit = imageAuditService.audit(fileMapper.queryById(updateUserDTO.getAvatar()).getFileKey());
                if (audit.getAuditStatus() != AuditStatus.SUCCESS) {
                    throw new BaseException(audit.getMsg());
                }
                oldUser.setAvatar(updateUserDTO.getAvatar());
        }

        if (!ObjectUtils.isEmpty(updateUserDTO.getDefaultFavoritesId())) {
            favoritesService.exist(userId, updateUserDTO.getDefaultFavoritesId());
        }

        oldUser.setSex(updateUserDTO.getSex());

        oldUser.setDefaultFavoritesId(updateUserDTO.getDefaultFavoritesId());

        this.updateById(oldUser);
    }

    @Override
    public Page<User> getFollows(BasePage basePage, Long userId) {
        Page<User> page = new Page<>();
        // 获取关注列表
        final List<Long> followIds = followService.getFollow(userId, basePage);
        if (ObjectUtils.isEmpty(followIds)) return page;
        // 获取粉丝列表
        final HashSet<Long> fans = new HashSet<>();
        // 这里需要将数据转换，因为存到redis中数值小是用int保存，取出来需要用long比较
        fans.addAll(followService.getFans(userId, null));
        Map<Long,Boolean> map = new HashMap<>();
        for (Long followId : followIds) {
            map.put(followId,fans.contains(followId));
        }

        // 获取头像

        final ArrayList<User> users = new ArrayList<>();
        final Map<Long, User> userMap = getBaseInfoUserToMap(map.keySet());
        final List<Long> avatarIds = userMap.values().stream().map(User::getAvatar).collect(Collectors.toList());
        for (Long followId : followIds) {
            final User user = userMap.get(followId);
            user.setEach(map.get(user.getId()));
            users.add(user);
        }
        page.setRecords(users);
        page.setTotal(users.size());

        return page;
    }

    @Override
    public Page<User> getFans( BasePage basePage, Long userId) {
        final Page<User> page = new Page<>();
        // 获取粉丝列表
        final List<Long> fansIds = followService.getFans(userId, basePage);
        if (ObjectUtils.isEmpty(fansIds)) return page;
        // 获取关注列表
        final HashSet<Long> followIds = new HashSet<>();
        followIds.addAll(followService.getFollow(userId,null));
        Map<Long,Boolean> map = new HashMap<>();
        // 遍历粉丝，查看关注列表中是否有
        for (Long fansId : fansIds) {
            map.put(fansId,followIds.contains(fansId));
        }
        final Map<Long, User> userMap = getBaseInfoUserToMap(map.keySet());
        final ArrayList<User> users = new ArrayList<>();
        // 遍历粉丝列表,保证有序性
        for (Long fansId : fansIds) {
            final User user = userMap.get(fansId);
            user.setEach(map.get(user.getId()));
            users.add(user);
        }

        page.setRecords(users);
        page.setTotal(users.size());
        return page;
    }

    @Override
    public boolean follows(Long followUserId,Long userId) {
        return followService.follows(followUserId,userId);
    }

    @Override
    public void subscribe(HashSet<Long> typeIds, Long userId) {
        if (ObjectUtils.isEmpty(typeIds)) return;
        // 校验分类
        List<Type> types = typeService.listByIds(typeIds);
        if (types.size() != typeIds.size()){
            throw new BaseException("有不存在的分类");
        }
        final ArrayList<UserSubscribe> userSubscribes = new ArrayList<>();
        for (Long typeId : typeIds) {
            final UserSubscribe userSubscribe = new UserSubscribe();
            userSubscribe.setUserId(userId);
            userSubscribe.setTypeId(typeId);
            userSubscribes.add(userSubscribe);
        }
        // 删除之前的
        userSubscribeService.remove(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId,userId));
        userSubscribeService.saveBatch(userSubscribes);
        // 初始化模型
        ModelVO modelVO = new ModelVO();
        modelVO.setUserId(UserHolder.get());
        // 获取分类下的标签
        List<String> labels = new ArrayList();
        for (Type type : types) {
            labels.addAll(type.buildLabel());
        }
        modelVO.setLabels(labels);
        // 初始化用户兴趣模型
        interestPushService.initUserModel(modelVO.getUserId(), modelVO.getLabels());

    }

    @Override
    public Collection<Type> listSubscribeType(Long userId) {
        if (userId == null){
            return Collections.EMPTY_SET;
        }
        List<Long> typeIds = userSubscribeService.list(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId))
                .stream().map(UserSubscribe::getTypeId).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(typeIds)){
            return Collections.EMPTY_LIST;
        }
        List<Type> types = typeService.list(
                new LambdaQueryWrapper<Type>().in(Type::getId,typeIds).select(Type::getId, Type::getName, Type::getIcon));
        return types;
    }

    @Override
    public Collection<Type> listNoSubscribeType(Long userId) {
        // 获取用户订阅的分类
        final Set<Long> set = listSubscribeType(userId).stream().map(Type::getId).collect(Collectors.toSet());
        // 获取所有分类
        final List<Type> allType = typeService.list((Wrapper<Type>) null);

        final ArrayList<Type> types = new ArrayList<>();
        for (Type type : allType) {
            if (!set.contains(type.getId())) {
                types.add(type);
            }
        }

        return types;
    }

    @Override
    public void addSearchHistory(Long userId, String search) {
        if (userId !=null){
            redisCacheUtil.zadd(RedisConstant.USER_SEARCH_HISTORY+userId,new Date().getTime(),search,RedisConstant.USER_SEARCH_HISTORY_TIME);
        }
    }

    @Override
    public Collection<String> getSearchHistory(Long userId) {
        List<String> searchHistory = new ArrayList<>();
        if (userId == null){
            throw new BaseException("请先登录");
        }
        searchHistory.add(redisCacheUtil.zGet(RedisConstant.USER_SEARCH_HISTORY+userId).toString());
        searchHistory = searchHistory.subList(0,searchHistory.size() < 10 ? searchHistory.size() : 10);
        return searchHistory;
    }

    @Override
    public void deleteSearchHistory(Long userId) {
        if (userId!=null){
            redisCacheUtil.del(RedisConstant.USER_SEARCH_HISTORY+userId);
        }
    }


    private Map<Long,User> getBaseInfoUserToMap(Collection<Long> userIds){
        List<User> users = new ArrayList<>();
        if (!ObjectUtils.isEmpty(userIds)){
            users = list(new LambdaQueryWrapper<User>().in(User::getId, userIds)
                    .select(User::getId, User::getNickName, User::getDescription
                            , User::getSex, User::getAvatar));
        }
        return users.stream().collect(Collectors.toMap(User::getId,Function.identity()));
    }
}
